<?php

class DBMConnectionManager {
	
	/**
	 * Store the connections
	 *
	 * @var array
	 */
	private $connections = array();
	
	
	/**
 	 * The instance of this object
 	 *
 	 * @var Object
 	 */
 	static private $instance = null;
	
 	
	/**
  	 * Singleton
  	 * @name getInstance
  	 * @access public
  	 * @return DBMConnectionManager
  	 */
  	static function getInstance(){
  		if(self::$instance == NULL){
  			self::$instance = new DBMConnectionManager();
  		}
  		return self::$instance;
  	}
  	
  	/**
  	 * Magic destructor of this manager
  	 * @return void
  	 */
  	public function __destruct(){
  		if(count($this->connections) > 0){
	  		foreach($this->connections as $id => $connection){
	  			$this->closeConnection($id);
	  		}	
  		}
  	}
 	
  	
  	/**
  	 * Return the connection object
  	 * @param string $identification The connection identification (default = 'default')
  	 * @return DBMConnection The connection
  	 * @throws InvalidConnectionException
  	 */
	public function getConnection($identification = "default"){
		if(isset($this->connections[$identification]) && is_object($this->connections[$identification])){
			return $this->connections[$identification];	
		} else {
			throw new InvalidConnectionException($identification);
		}
		
	}
	
	
	/**
 	 * Create a new connection with the database
 	 * @name createConnection
 	 * @access public
 	 * @param String $host The host
 	 * @param String $username The userna,e
 	 * @param String $password The password
 	 * @param String $database The database
 	 * @param String $identification Identification of this connection in the application
 	 * @return boolean
 	 */
 	public function createConnection($type, $host, $username, $password, $database, $identification = "default", $cacheType){
 		// get the type of the connection
 		if($type == DBManager::TYPE_MYSQL){
 			$connection = new DBMMySqlConnection();
 		} elseif ($type == DBManager::TYPE_POSTGRESQL){
 			$connection = new DBMPostgreSqlConnection();
 		} elseif ($type == DBManager::TYPE_MSSQL){
 			$connection = new DBMSqlServerConnection();
 		} else {
 			throw new UnsupportedDatabaseException("[unknow]");
 		}
 		
 		
 		// set the data
 		$connection->setIdentification($identification);
 		$connection->setType($type);
 		$connection->setAutoCommit(false);
 		$connection->setOnTransaction(false);
 		$connection->setHost($host);
 		$connection->setUsername($username);
 		$connection->setPassword($password);
 		$connection->setDatabase($database);
 		
 		// check the cache type
 		if($cacheType == "execution"){
 			$connection->setCache(new DBMExecutionCache());
 		} elseif($cacheType == "session") {
 			$connection->setCache(new DBMSessionCache());
 		}
 		
 		// connect
 		$connection->connect();
 		 		
 		// store the connection
 		$this->connections[$identification] = $connection;
		
 		// return
		return true;
 	}

 	
	/**
	 * Close the connection
 	 * @name closeConnection
 	 * @access public
 	 * @param String $identification Identifica��o da conex�o
 	 * @return boolean
 	 */
 	public function closeConnection($identification = "default"){
 		// get the connection
 		$connection = $this->getConnection($identification);
 		
 		// check the integrity
 		if(is_null($connection)){
 			return null;
 		}
 		
 		// disconnect
 		$connection->disconnect();

 		// check the cache
 		if(!is_null($connection->getCache())){
 			$connection->getCache()->finalize();
 		}
 	}

 	
	/**
	 * Create the connections from the configuration xml file
	 *
	 * @param string $path The XML path
	 */
	public function createConnectionsFromXML($path){
 		// check if the path exists and is readable
 		if(!is_file($path) || !is_readable($path)){
 			throw new Exception("The configuration file (".$path.") for the database connections doesn't exists or could not be readed!");
		}

		// start the dom reader
		$dom = new DOMDocument();
		
		// load the data
		@$dom->load($path);
		
		// get the connections and the aliases
		$connections = $dom->getElementsByTagName("connection");
		$aliases = $dom->getElementsByTagName("alias");

		// search the connections 
		for($i = 0; $i < $connections->length; $i++){
			$conn = $connections->item($i);
			
			// get the data
			$host		= utf8_decode($conn->getAttribute("host"));
			$user		= utf8_decode($conn->getAttribute("user"));
			$pass		= utf8_decode($conn->getAttribute("pass"));
			$db			= utf8_decode($conn->getAttribute("database"));
			$type		= utf8_decode($conn->getAttribute("type"));
			$name		= utf8_decode($conn->getAttribute("name"));
			$cacheType	= utf8_decode($conn->getAttribute("cache"));
			
			// format the data
			if($cacheType == "" || $cacheType == "execution"){
				$cache = "execution";
			} elseif($cacheType == "session") {
				$cache = "session";
			}

			// start the connection
			$this->createConnection($type, $host, $user, $pass, $db, $name, $cache);
		}

		// search the aliases
		for($i = 0; $i < $aliases->length; $i++){
			//$alias = $aliases->item($i);
			//$manager->createAlias(utf8_decode($alias["name"]), utf8_decode($alias["target"]));
		}
 	}

 	
	/**
	 * Start a new transaction on the connection $identification
 	 * @name startTransaction
 	 * @access public
 	 * @param String $identification Identifica��o da conex�o
 	 * @param boolean $autocommit Seta o valor do autocommit
 	 * @return boolean
 	 */
 	public function startTransaction($autocommit = true, $identification = 'default'){
 		$error = false;
 		if(!isset($this->db[$identification])){
 			throw new Exception("A conex�o " . $identification . " n�o existe!");
 		}
 		if($this->haveTransaction($identification)){
 			return true;
 		}
 		
 		try{
	 		$type = $this->db[$identification]["type"];
 			if($type == self::TYPE_MYSQL || $type == self::TYPE_POSTGRESQL){
				$this->runQuery("START TRANSACTION");	 			
	 		} elseif($type == self::TYPE_MSSQL) {
	 			$this->runQuery("BEGIN TRANSACTION");
	 		} else {
	 			$error = true;
	 		}
 		} catch(Exception $e){
 			$error = true;
 		}
 		
 		if(!$error){
 			$this->db[$identification]["transaction"] 	=  true;
 			$this->db[$identification]["autocommit"] 	=  $autocommit;
 			return true;
 		}
 		return false;
 	}
 	
 	
 	/**
 	 * Finish a started trahsaction
 	 * @name finishTransaction
 	 * @access public
 	 * @param String $identification Identifica��o da conex�o
 	 * @param String $action A a��o a ser executada [COMMIT ou ROLLBACK]
 	 * @return boolean
 	 */
 	public function finishTransaction($action, $identification = 'default'){
 		$error = false;
 		if($action != self::TRANSACTION_COMMIT && $action != self::TRANSACTION_ROLLBACK){
 			throw new Exception("Invalid transaction finish action!");
 		}
 		if(!isset($this->db[$identification])){
 			throw new Exception("A conex�o " . $identification . " n�o existe!");
 		}
 		if(!$this->db[$identification]["transaction"]){
 			return false;
 		}
 		
 		try{
	 		$type = $this->db[$identification]["type"];
 			if($type == self::TYPE_MYSQL || $type == self::TYPE_POSTGRESQL){
 				if($action == self::TRANSACTION_COMMIT){
 					$this->runQuery("COMMIT;");	
 				} else {
 					$this->runQuery("ROLLBACK;");
 				}
	 		} elseif($type == self::TYPE_MSSQL) {
	 			if($action == self::TRANSACTION_COMMIT){
					$this->runQuery("COMMIT TRANSACTION;");	
 				} else {
 					$this->runQuery("ROLLBACK TRANSACTION;");
 				}
	 		} else {
	 			$error = true;
	 		}
 		} catch(Exception $e){
 			$error = true;
 		}
 		
 		if(!$error){
 			$this->db[$identification]["transaction"] 	=  false;
 			$this->db[$identification]["autocommit"] 	=  false;
 			return true;
 		}
 		
 		return false;
 	}
}

?>